package edu.stthomas.edu.seis770.simpleclock;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.WindowConstants;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Calendar;
import java.util.Observable;
import java.util.Observer;
import java.util.Timer;
import java.util.TimerTask;
import java.awt.Font;
import javax.swing.SwingConstants;

public class ClockUI implements Observer {
    private final ClockModel clockModel;

    private boolean guiIsInitialized = false;

    // GUI components
    private JFrame frame;
    private JLabel hoursLabel;
    private JLabel minutesLabel;
    private JLabel secondsLabel;
    private JButton incrementButton;
    private JButton decrementButton;
    private JButton changeModeButton;
    private JButton cancelButton;

    private ClockUI() {
        // Initialize the clock to current time
        Calendar now = Calendar.getInstance();
        clockModel = new ClockModel(now.get(Calendar.SECOND), now.get(Calendar.MINUTE), now.get(Calendar.HOUR));
        // Register this instance of clockUI to be an observer of clockModel
        clockModel.addObserver(this);
        Timer secondsTicker = new Timer();
        // Execute timerTick state transition every second. secondsTicker thread can be closed by calling its method cancel
        secondsTicker.schedule(new TimerTask() {public void run() {clockModel.timerTick();}}, 0, 1000);

        // Show the UI
        initUI();


    }

    // This is the entry point of simple clock app
    public static void main(String[] args) {
        new ClockUI();
    }


    private void initUI() {

        hoursLabel = new JLabel();
        hoursLabel.setHorizontalAlignment(SwingConstants.CENTER);
        hoursLabel.setFont(new Font("Tahoma", Font.PLAIN, 16));
        hoursLabel.setBounds(73, 15, 55, 79);
        hoursLabel.setText(Integer.toString(clockModel.getHours()));

        minutesLabel = new JLabel();
        minutesLabel.setHorizontalAlignment(SwingConstants.CENTER);
        minutesLabel.setFont(new Font("Tahoma", Font.PLAIN, 16));
        minutesLabel.setBounds(166, 16, 41, 78);
        minutesLabel.setText(Integer.toString(clockModel.getMinutes()));

        secondsLabel = new JLabel();
        secondsLabel.setHorizontalAlignment(SwingConstants.CENTER);
        secondsLabel.setFont(new Font("Tahoma", Font.PLAIN, 16));
        secondsLabel.setBounds(255, 13, 45, 83);
        secondsLabel.setText(Integer.toString(clockModel.getSeconds()));

        incrementButton = new JButton("+");
        incrementButton.setBounds(24, 107, 41, 25);
        incrementButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                clockModel.increment();
            }
        });

        decrementButton = new JButton("-");
        decrementButton.setBounds(83, 107, 45, 25);
        decrementButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                clockModel.decrement();
            }
        });

        changeModeButton = new JButton("Change Mode");
        changeModeButton.setBounds(151, 107, 132, 25);
        changeModeButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                clockModel.changeMode();
            }
        });

        cancelButton = new JButton("Cancel");
        cancelButton.setBounds(295, 109, 75, 25);
        cancelButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                clockModel.cancel();
            }
        });

        frame = new JFrame("Simple UI");
        frame.setPreferredSize(new Dimension(400, 200));
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        frame.getContentPane().setLayout(null);
        frame.getContentPane().add(hoursLabel);
        frame.getContentPane().add(minutesLabel);
        frame.getContentPane().add(secondsLabel);
        frame.getContentPane().add(incrementButton);
        frame.getContentPane().add(decrementButton);
        frame.getContentPane().add(changeModeButton);
        frame.getContentPane().add(cancelButton);
        frame.setVisible(true);
        frame.pack();

        guiIsInitialized = true;

        // Need to hide set buttons at the beginning
        hideSetButtons();
    }

    // This is the method that gets executed once clockModel notifies us of changes
    public void update(Observable obs, Object obj) {
        if (guiIsInitialized) {
            if (obj != null && obj instanceof ClockState) {
                ClockState clockState = (ClockState) obj;
                if (clockState instanceof DisplayTime) {
                    // hide incrementButton, decrementButton and cancel buttons
                    hideSetButtons();
                    // highlight nothing
                    highlight(null);
                } else if (clockState instanceof SetHours) {
                    // show incrementButton, decrementButton and cancel buttons
                    showSetButtons();
                    highlight(hoursLabel);


                } else if (clockState instanceof SetMinutes) {
                    showSetButtons();
                    highlight(minutesLabel);
                } else if (clockState instanceof SetSeconds) {
                    showSetButtons();
                    highlight(secondsLabel);
                }
            }
            hoursLabel.setText(Integer.toString(clockModel.getHours()));
            minutesLabel.setText(Integer.toString(clockModel.getMinutes()));
            secondsLabel.setText(Integer.toString(clockModel.getSeconds()));
        }
    }

    private void hideSetButtons() {
        cancelButton.setVisible(false);
        incrementButton.setVisible(false);
        decrementButton.setVisible(false);
    }

    private void showSetButtons() {
        cancelButton.setVisible(true);
        incrementButton.setVisible(true);
        decrementButton.setVisible(true);
    }

    // This might be inefficient . will tune it later
    private void highlight(JLabel label) {
        for (Component component : frame.getContentPane().getComponents()) {
            if (component instanceof JLabel) {
                JLabel currentLabel = (JLabel) component;
                if (currentLabel == label) {
                    currentLabel.setOpaque(true);
                    currentLabel.setBackground(Color.RED);
                } else {
                    // This will reset the background to default
                    currentLabel.setBackground(null);
                }
            }
        }
    }

}
